/* *
 * --ライセンスについて--
 *
 * 「本ファイルの内容は Mozilla Public License Version 1.1 (「本ライセンス」)
 * の適用を受けます。
 * 本ライセンスに従わない限り本ファイルを使用することはできません。
 * 本ライセンスのコピーは http://www.mozilla.org/MPL/ から入手できます。
 *
 * 本ライセンスに基づき配布されるソフトウェアは、「現状のまま」で配布されるものであり、
 * 明示的か黙示的かを問わず、いかなる種類の保証も行われません。
 * 本ライセンス上の権利および制限を定める具体的な文言は、本ライセンスを参照してください。
 *
 * オリジナルコードおよび初期開発者は、N_H (h.10x64@gmail.com) です。
 *
 * N_H によって作成された部分の著作権表示は次のとおりです。
 *
 * Copyright (C)N_H 2012
 *
 * このファイルの内容は、上記に代えて、
 * GNU General License version2 以降 (以下 GPL とする)、
 * GNU Lesser General Public License Version 2.1 以降 (以下 LGPL とする)、
 * の条件に従って使用することも可能です。
 * この場合、このファイルの使用には上記の条項ではなく GPL または LGPL の条項が適用されます。
 * このファイルの他者による使用を GPL または LGPL の条件によってのみ許可し、
 * MPL による使用を許可したくない対象者は、上記の条項を削除することでその意思を示し、
 * 上記条項を GPL または LGPL で義務付けられている告知およびその他の条項に置き換えてください。
 * 対象者が上記の条項を削除しない場合、
 * 受領者は MPL または GPL または LGPL ライセンスのいずれによってもこのファイルを
 * 使用することができます。」
 *
 * -- License --
 *
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License。You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND、either express or implied。See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *   N_H (h.10x64@gmail.com).
 *
 * Portions created by the Initial Developer are Copyright (C)N_H 2012
 * the Initial Developer。All Rights Reserved.
 *
 * Alternatively、the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL")、or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above。If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL、and not to allow others to
 * use your version of this file under the terms of the MPL、indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL。If you do not delete
 * the provisions above、a recipient may use your version of this file under
 * the terms of any one of the MPL、the GPL or the LGPL.
 *
 * */
package com.magiciansforest.audio.soundrenderer.gui;

import com.magiciansforest.audio.soundrenderer.event.FramePositionChangeEvent;
import com.magiciansforest.audio.soundrenderer.event.FramePositionChangeEventListener;
import com.magiciansforest.audio.soundrenderer.event.MovieStatusChangeEvent;
import com.magiciansforest.audio.soundrenderer.event.MovieStatusChangeEventListener;
import com.magiciansforest.audio.soundrenderer.logic.Movie;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.controls.Controller;
import de.lessvoid.nifty.controls.Label;
import de.lessvoid.nifty.controls.label.LabelControl;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.events.NiftyMousePrimaryClickedEvent;
import de.lessvoid.nifty.elements.events.NiftyMousePrimaryClickedMovedEvent;
import de.lessvoid.nifty.elements.render.ImageRenderer;
import de.lessvoid.nifty.input.NiftyInputEvent;
import de.lessvoid.nifty.render.NiftyImage;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.xml.xpp3.Attributes;
import java.text.DecimalFormat;
import java.util.Properties;

/**
 *
 * @author N_H
 */
public class MoviePositionSliderControl implements Controller, FramePositionChangeEventListener, MovieStatusChangeEventListener {

    private Movie mov;
    private Nifty nifty;
    private Element self;
    private Element slider, border, startButton, recButton, label;
    private Properties properties;
    private Attributes attributes;
    private boolean doesUpdate;
    private NiftyImage startButtonImg, startButtonPressedImg, recButtonImg, recButtonPressedImg;
    private Label digitLabel;
    private static final DecimalFormat df = new DecimalFormat("00000");

    public void setMovie(Movie mov) {
        this.mov = mov;
        mov.addFramePositionChangeEvnetListener(this);
        mov.addMovieStatusChangeEventListener(this);
        digitLabel.setText(df.format(mov.getMovieFramePosition()) + "/" + df.format(mov.getLastFrameNo()));
    }

    @Override
    public void bind(final Nifty nifty, final Screen screen, final Element element, final Properties properties, final Attributes attributes) {
        this.self = element;
        this.nifty = nifty;
        this.properties = properties;
        this.attributes = attributes;
        this.doesUpdate = true;

        this.border = self.findElementByName("border");
        this.slider = self.findElementByName("slider");
        this.startButton = self.findElementByName("startButton");
        this.recButton = self.findElementByName("recButton");
        this.label = self.findElementByName("digitLabel");
        this.digitLabel = self.findControl("digitLabel", LabelControl.class);

        this.startButtonImg = nifty.createImage("GUI/SoundPositionBarStartButton.png", false);
        this.startButtonPressedImg = nifty.createImage("GUI/SoundPositionBarStartButton_p.png", false);
        this.recButtonImg = nifty.createImage("GUI/SoundPositionBarRecButton.png", false);
        this.recButtonPressedImg = nifty.createImage("GUI/SoundPositionBarRecButton_p.png", false);
    }

    @Override
    public void init(Properties properties, Attributes attributes) {
    }

    @Override
    public boolean inputEvent(NiftyInputEvent evt) {
        return false;
    }

    @Override
    public void onFocus(boolean onFocus) {
    }

    @Override
    public void onStartScreen() {
    }

    @Override
    public void changeFramePosition(FramePositionChangeEvent e) {
        setFramePosition(e.getPosition());
    }

    @Override
    public void changeMovieStatus(MovieStatusChangeEvent e) {
        if (e.getStatus() == Movie.PAUSED) {
            startButton.getRenderer(ImageRenderer.class).setImage(startButtonImg);
            recButton.getRenderer(ImageRenderer.class).setImage(recButtonImg);
        } else if (e.getStatus() == Movie.STARTED) {
            startButton.getRenderer(ImageRenderer.class).setImage(startButtonPressedImg);
        } else if (e.getStatus() == Movie.RENDERING) {
            startButton.getRenderer(ImageRenderer.class).setImage(startButtonPressedImg);
            recButton.getRenderer(ImageRenderer.class).setImage(recButtonPressedImg);
        }
    }

    public void mouseDragged(NiftyMousePrimaryClickedMovedEvent evt) {
        if (!doesClickButton(evt.getMouseX(), evt.getMouseY())) {
            setSliderPosition(evt.getMouseX(), evt.getMouseY());
        }
    }

    public void mouseClicked(NiftyMousePrimaryClickedEvent evt) {
        int x = evt.getMouseX(), y = evt.getMouseY();

        if (doesClickButton(evt.getMouseX(), evt.getMouseY())) {
            processButtons(evt.getMouseX(), evt.getMouseY());
        } else {
            setSliderPosition(evt.getMouseX(), evt.getMouseY());
        }
    }

    private void setFramePosition(int frameNo) {
        if (doesUpdate) {
            doesUpdate = false;
            int w = (int) Math.round((float) frameNo / mov.getLastFrameNo() * self.findElementByName("border").getWidth());
            self.findElementByName("slider").setWidth(w);
            digitLabel.setText(df.format(mov.getMovieFramePosition()) + "/" + df.format(mov.getLastFrameNo()));
            doesUpdate = true;
        }
    }

    private void setSliderPosition(int mouseX, int mouseY) {
        if (doesUpdate && mov.getMovieStatus() != Movie.RENDERING) {
            doesUpdate = false;
            int relX = Math.max(Math.min(mouseX - self.findElementByName("border").getX(), self.findElementByName("border").getWidth()), 2);
            int relY = Math.max(Math.min(mouseY - self.getY(), self.getHeight()), 0);
            self.findElementByName("slider").setWidth(relX);

            int framePosition = (int) Math.round((float) (relX - 2) / (self.findElementByName("border").getWidth() - 2) * mov.getLastFrameNo());
            mov.setFramePosition(framePosition);
            digitLabel.setText(df.format(mov.getMovieFramePosition()) + "/" + df.format(mov.getLastFrameNo()));
            doesUpdate = true;
        }
    }

    private boolean doesClickButton(int mouseX, int mouseY) {
        if (mouseX >= startButton.getX() && mouseX <= recButton.getX() + recButton.getWidth()
                && mouseY >= self.getY() && mouseY <= self.getY() + self.getHeight()) {
            return true;
        } else {
            return false;
        }
    }

    private void processButtons(int mouseX, int mouseY) {
        if (mouseX > startButton.getX() && mouseX < startButton.getX() + startButton.getWidth()) {
            clickStartButton();
        } else if (mouseX > recButton.getX() && mouseX < recButton.getX() + recButton.getWidth()) {
            clickRecButton();
        }
    }

    private void clickStartButton() {
        if (mov.getMovieStatus() == Movie.PAUSED) {
            mov.setMovieStatus(Movie.STARTED);
        } else {
            mov.setMovieStatus(Movie.PAUSED);
        }
    }

    private void clickRecButton() {
        mov.setMovieStatus(Movie.RENDERING);
    }
}
